﻿using Microsoft.Build.Evaluation;
using NuGet;
using OD.ProjectCustomizationTool.Helpers;
using OD.ToolBox.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OD.ProjectCustomizationTool
{
    internal abstract class ProjectUpdaterBase : ProjectToolBase
    {
        #region Methods

        /// <summary>
        /// <see cref="Microsoft.Build.Evaluation.Project.SetProperty"/>
        /// </summary>
        protected ProjectProperty SetProjectProperty(string name, string unevaluatedValue)
        {
            var result = default(ProjectProperty);

            var originalValue = this.CurrentProject.GetPropertyValue(name);
            if (originalValue != unevaluatedValue)
            {
                this.Monitor.Logger.WriteLine("Setting project property '" + name + "' to '" + unevaluatedValue + "'.");
                result = this.CurrentProject.SetProperty(name, unevaluatedValue);
            }

            return result;
        }

        /// <summary>
        /// <see cref="Microsoft.Build.Evaluation.Project.AddItem(string, string)"/>
        /// </summary>
        protected IList<ProjectItem> AddItemAsLink(string itemType, string unevaluatedInclude)
        {
            var result = default(IList<ProjectItem>);

            var originalValue = this.CurrentProject.GetItems(itemType);
            if (originalValue == null || originalValue.Count() <= 0)
            {
                this.Monitor.Logger.WriteLine("Adding linked item '" + unevaluatedInclude + "'");

                result = this.CurrentProject.AddItem(itemType, unevaluatedInclude);
                var linkName = Path.GetFileName(unevaluatedInclude);
                foreach (var item in result)
                {
                    item.SetMetadataValue(Properties.Resources.LinkProjectMetadata, linkName);
                }
            }

            return result;
        }

        /// <summary>
        /// Add a reference to an assembly.
        /// </summary>
        /// <param name="package">The NuGet package to consider ;</param>
        /// <param name="assembly">The package assembly to reference.</param>
        protected IList<ProjectItem> AddReference(IPackage package, IPackageAssemblyReference assembly)
        {
            if (package == null)
            {   // This code has been generated from the 'argnull' custom snippet.
                throw new ArgumentNullException("package");
            }
            if (assembly == null)
            {   // This code has been generated from the 'argnull' custom snippet.
                throw new ArgumentNullException("assembly");
            }

            var result = default(IList<ProjectItem>);
            var itemType = assembly.ShortName();

            SourceControlHelper.Add(package.FullPath(this.CurrentProject), this.Monitor.Logger);

            var originalValue = this.CurrentProject.GetItems(Properties.Resources.ReferenceProjectItemType)
                .Where(x => String.Equals(x.UnevaluatedInclude, itemType));
            if (originalValue == null || originalValue.Count() <= 0)
            {
                this.Monitor.Logger.WriteLine("Adding reference to '" + itemType + "'");

                result = this.CurrentProject.AddItem(Properties.Resources.ReferenceProjectItemType, itemType);
                var hintPath = PathHelper.BuildRelative(
                    Directory.GetParent(this.CurrentProject.FullPath).FullName,
                    assembly.GetFullPath(this.CurrentProject, package));
                foreach (var projectItem in result)
                {
                    projectItem.SetMetadataValue(Properties.Resources.HintPathProjectReferenceMetadata, hintPath);
                }
            }

            return result;
        }

        #endregion

    }
}
